luafandomcom-20200214-history
TestExpand
expand = loadstring([[ ---- -- Expand.lua local strfind = string.find local strsub = string.sub local push = table.insert local pop = table.remove local concat = table.concat local statements = {} for w in string.gfind('do if for while repeat', '%a+') do statementsw = true end local function expand(str, ...) assert(type(str) 'string', 'expecting string') local searchlist = arg local estring,evar function estring(str) local b,e,i b,i = strfind(str, '%$.') if not b then return str end local R, pos = {}, 1 repeat b,e = strfind(str, '^%b{}', i) if b then push(R, strsub(str, pos, b-2)) push(R, evar(strsub(str, b+1, e-1))) i = e+1 pos = i else b,e = strfind(str, '^%b()', i) if b then push(R, strsub(str, pos, b-2)) push(R, evar(strsub(str, b+1, e-1))) i = e+1 pos = i elseif strfind(str, '^%a', i) then push(R, strsub(str, pos, i-2)) push(R, evar(strsub(str, i, i))) i = i+1 pos = i elseif strfind(str, '^%$', i) then push(R, strsub(str, pos, i)) i = i+1 pos = i end end b,i = strfind(str, '%$.', i) until not b push(R, strsub(str, pos)) return concat® end local function search(index) for _,symt in ipairs(searchlist) do local ts = type(symt) local value if ts 'function' then value = symt(index) elseif ts 'table' or ts 'userdata' then value = symtindex if type(value) 'function' then value = value(symt) end else error'search item must be a function, table or userdata' end if value ~= nil then return value end end error('unknown variable: '.. index) end local function elist(var, v, str, sep) local tab = search(v) if tab then assert(type(tab) 'table', 'expecting table from: '.. var) local R = {} push(searchlist, 1, tab) push(searchlist, 1, false) for _,elem in ipairs(tab) do searchlist1 = elem push(R, estring(str)) end pop(searchlist, 1) pop(searchlist, 1) return concat(R, sep) else return end end local function get(tab,index) for _,symt in ipairs(searchlist) do local ts = type(symt) local value if ts 'function' then value = symt(index) elseif ts 'table' or ts 'userdata' then value = symtindex else error'search item must be a function, table or userdata' end if value ~= nil then tabindex = value -- caches value and prevents changing elements return value end end end function evar(var) if strfind(var, '^_%a_%w*$') then -- ${vn} return estring(tostring(search(var))) end local b,e,cmd = strfind(var, '^(%a+)%s.') if cmd 'foreach' then -- ${foreach vn xxx} or ${foreach vn/sep/xxx} local vn,s b,e,vn,s = strfind(var, '^(_%a_%w*)(%s%p).', e) if vn then if strfind(s, '%s') then return elist(var, vn, strsub(var, e), ) end b = strfind(var, s, e, true) if b then return elist(var, vn, strsub(var, b+1), strsub(var,e,b-1)) end end error('syntax error in: '.. var, 2) elseif cmd 'when' then -- $(when vn xxx) local vn b,e,vn = strfind(var, '^(_%a_%w*)%s.', e) if vn then local t = search(vn) if not t then return end local s = strsub(var,e) if type(t) 'table' or type(t) 'userdata' then push(searchlist, 1, t) s = estring(s) pop(searchlist, 1) return s else return estring(s) end end error('syntax error in: '.. var, 2) else if statementscmd then -- do if for while repeat var = 'local OUT="" '.. var ..' return OUT' else -- expression var = 'return '.. var end local f = assert(loadstring(var)) local t = searchlist1 assert(type(t) 'table' or type(t) 'userdata', 'expecting table') setfenv(f, setmetatable({}, {__index=get, __newindex=t})) return estring(tostring(f())) end end return estring(str) end return expand ]])() template = [[ variables: $v environment: ${HOME} list: ${for i=1,list.n do OUT = table.concat{ OUT, ' listi, ' = ', listi, '\n'} end} ]] L = {'A', 'B', 'C', 'D', n=4} local x = { v = 'variable', list = L } io.write(expand(template, x, _G, os.getenv))